Flutter TextField – Detailed Notes
Flutter TextField is a Material Design input widget that allows users to enter text using a hardware or on-screen keyboard. It is commonly used for login forms, registration forms, search boxes, chat applications, feedback forms, profile editing, and many other Flutter applications. Flutter provides both TextField and TextFormField; TextFormField is useful when the input needs to be integrated with a Form and validation. :contentReference[oaicite:0]{index=0}
1. What is TextField?
A TextField is a Flutter widget used to accept editable text from the user. It provides a convenient interface for collecting input such as names, email addresses, passwords, phone numbers, search keywords, and messages.
Common Uses
- User name input
- Email address input
- Password input
- Phone number input
- Search boxes
- Chat messages
- Address fields
- Comments and feedback
- Multiline descriptions
Basic Syntax
TextField(
decoration: InputDecoration(
labelText: 'Enter your name',
),
)
2. Creating a Basic TextField
The simplest TextField can be created by placing the widget inside a Flutter layout.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: const Text('TextField Example'),
),
body: const Padding(
padding: EdgeInsets.all(20),
child: TextField(),
),
),
);
}
}
By default, a Material TextField has an underline decoration. The appearance can be customized using InputDecoration. :contentReference[oaicite:1]{index=1}
3. TextField with Hint Text
hintText displays helpful information inside the input field before the user enters text.
TextField(
decoration: InputDecoration(
hintText: 'Enter your name',
),
)
Example:
TextField(
decoration: InputDecoration(
hintText: 'Enter your email address',
border: OutlineInputBorder(),
),
)
4. TextField with Label
The labelText property displays a label describing what the user should enter.
TextField(
decoration: InputDecoration(
labelText: 'Username',
border: OutlineInputBorder(),
),
)
When the field receives focus or contains text, the label can move to the top of the input area depending on the decoration style.
5. InputDecoration
InputDecoration is used to customize the visual appearance of a TextField. It supports labels, hints, borders, icons, helper text, error text, prefixes, suffixes, and other decoration features. :contentReference[oaicite:2]{index=2}
Important InputDecoration Properties
| Property | Purpose |
|---|
labelText | Displays a label for the field. |
hintText | Provides an example or instruction inside the field. |
helperText | Displays additional information below the field. |
errorText | Displays an error message. |
prefixIcon | Adds an icon before the input. |
suffixIcon | Adds an icon after the input. |
prefixText | Displays text before the input. |
suffixText | Displays text after the input. |
filled | Controls whether the input background is filled. |
fillColor | Sets the background color when filled. |
border | Defines the default border. |
enabledBorder | Defines the border when the field is enabled but not focused. |
focusedBorder | Defines the border when the field is focused. |
6. OutlineInputBorder
OutlineInputBorder creates a border around the complete input field.
TextField(
decoration: InputDecoration(
labelText: 'Full Name',
border: OutlineInputBorder(),
),
)
Rounded Border
TextField(
decoration: InputDecoration(
labelText: 'Email',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
),
)
7. Prefix Icon
prefixIcon places an icon at the beginning of the input field.
TextField(
decoration: InputDecoration(
labelText: 'Email',
prefixIcon: Icon(Icons.email),
border: OutlineInputBorder(),
),
)
Example: Username Field
TextField(
decoration: InputDecoration(
labelText: 'Username',
hintText: 'Enter your username',
prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
),
)
8. Suffix Icon
suffixIcon places an icon at the end of the input field.
TextField(
decoration: InputDecoration(
labelText: 'Search',
suffixIcon: Icon(Icons.search),
border: OutlineInputBorder(),
),
)
Clear Button Example
TextField(
decoration: InputDecoration(
labelText: 'Search',
suffixIcon: IconButton(
icon: Icon(Icons.clear),
onPressed: () {},
),
border: OutlineInputBorder(),
),
)
9. TextEditingController
TextEditingController allows you to control and read the text inside a TextField. It can be used to access the current value, set an initial value, modify the text, and listen for changes. Flutter recommends disposing of the controller when it is no longer needed. :contentReference[oaicite:3]{index=3}
Example
class NameScreen extends StatefulWidget {
const NameScreen({super.key});
@override
State createState() => _NameScreenState();
}
class _NameScreenState extends State {
final TextEditingController nameController =
TextEditingController();
@override
void dispose() {
nameController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Controller Example'),
),
body: Padding(
padding: const EdgeInsets.all(20),
child: Column(
children: [
TextField(
controller: nameController,
decoration: const InputDecoration(
labelText: 'Name',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
print(nameController.text);
},
child: const Text('Get Name'),
),
],
),
),
);
}
}
Reading Text
String name = nameController.text;
Setting Text
nameController.text = 'John Doe';
10. Initial Text in TextField
You can provide initial text using a TextEditingController.
final TextEditingController controller =
TextEditingController(text: 'John Doe');
TextField(
controller: controller,
)
11. onChanged
The onChanged callback is called whenever the user changes the text in the TextField. :contentReference[oaicite:4]{index=4}
TextField(
onChanged: (value) {
print('Current value: $value');
},
)
Example: Live Character Display
class CharacterExample extends StatefulWidget {
const CharacterExample({super.key});
@override
State createState() => _CharacterExampleState();
}
class _CharacterExampleState extends State {
int count = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
onChanged: (value) {
setState(() {
count = value.length;
});
},
),
Text('Characters: $count'),
],
);
}
}
12. onSubmitted
onSubmitted runs when the user submits the text, commonly by pressing the action button on the software keyboard. :contentReference[oaicite:5]{index=5}
TextField(
onSubmitted: (value) {
print('Submitted: $value');
},
)
Search Example
TextField(
textInputAction: TextInputAction.search,
onSubmitted: (value) {
print('Searching for: $value');
},
decoration: InputDecoration(
hintText: 'Search products',
prefixIcon: Icon(Icons.search),
border: OutlineInputBorder(),
),
)
13. onEditingComplete
onEditingComplete is called when editing is completed. It can be customized when you need specific behavior after the user finishes editing.
TextField(
onEditingComplete: () {
print('Editing completed');
},
)
14. Password TextField
Password fields can hide entered characters by setting obscureText: true. :contentReference[oaicite:6]{index=6}
TextField(
obscureText: true,
decoration: InputDecoration(
labelText: 'Password',
prefixIcon: Icon(Icons.lock),
border: OutlineInputBorder(),
),
)
Password Visibility Toggle
class PasswordField extends StatefulWidget {
const PasswordField({super.key});
@override
State createState() => _PasswordFieldState();
}
class _PasswordFieldState extends State {
bool hidePassword = true;
@override
Widget build(BuildContext context) {
return TextField(
obscureText: hidePassword,
decoration: InputDecoration(
labelText: 'Password',
prefixIcon: const Icon(Icons.lock),
suffixIcon: IconButton(
icon: Icon(
hidePassword
? Icons.visibility
: Icons.visibility_off,
),
onPressed: () {
setState(() {
hidePassword = !hidePassword;
});
},
),
border: const OutlineInputBorder(),
),
);
}
}
15. Keyboard Type
The keyboardType property controls the type of keyboard suggested by the platform.
TextField(
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email',
border: OutlineInputBorder(),
),
)
Common Keyboard Types
| Keyboard Type | Usage |
|---|
TextInputType.text | General text |
TextInputType.emailAddress | Email addresses |
TextInputType.phone | Phone numbers |
TextInputType.number | Numbers |
TextInputType.datetime | Date/time input |
TextInputType.url | Website URLs |
TextInputType.multiline | Multiline text |
16. Text Capitalization
textCapitalization controls how entered text is automatically capitalized.
TextField(
textCapitalization: TextCapitalization.words,
decoration: InputDecoration(
labelText: 'Full Name',
border: OutlineInputBorder(),
),
)
Available Options
TextCapitalization.none
TextCapitalization.characters
TextCapitalization.words
TextCapitalization.sentences
17. maxLength
maxLength limits the number of characters that can be entered into the field. Flutter also provides a character counter when this property is used. :contentReference[oaicite:7]{index=7}
TextField(
maxLength: 20,
decoration: InputDecoration(
labelText: 'Username',
border: OutlineInputBorder(),
),
)
Example
TextField(
maxLength: 10,
keyboardType: TextInputType.phone,
decoration: InputDecoration(
labelText: 'Phone Number',
border: OutlineInputBorder(),
),
)
18. maxLines and Multiline TextField
By default, a TextField is single-line. The maxLines property can be used to create a multiline input. :contentReference[oaicite:8]{index=8}
TextField(
maxLines: 5,
decoration: InputDecoration(
labelText: 'Description',
hintText: 'Write your description',
border: OutlineInputBorder(),
),
)
Unlimited Multiline Input
TextField(
maxLines: null,
decoration: InputDecoration(
labelText: 'Message',
border: OutlineInputBorder(),
),
)
19. minLines
minLines specifies the minimum number of lines occupied by the input.
TextField(
minLines: 3,
maxLines: 5,
decoration: InputDecoration(
labelText: 'Comments',
border: OutlineInputBorder(),
),
)
20. Text Alignment
The textAlign property controls the horizontal alignment of entered text.
TextField(
textAlign: TextAlign.center,
decoration: InputDecoration(
border: OutlineInputBorder(),
),
)
Common Values
TextAlign.left
TextAlign.center
TextAlign.right
TextAlign.justify
TextAlign.start
TextAlign.end
21. Styling TextField
Text Style
TextField(
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
),
decoration: const InputDecoration(
labelText: 'Name',
border: OutlineInputBorder(),
),
)
Filled TextField
TextField(
decoration: InputDecoration(
labelText: 'Email',
filled: true,
fillColor: Colors.grey,
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
)
22. Focused Border
You can customize the border shown when the TextField receives focus.
TextField(
decoration: InputDecoration(
labelText: 'Email',
border: OutlineInputBorder(),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.blue,
width: 2,
),
),
),
)
Enabled and Focused Borders
TextField(
decoration: InputDecoration(
labelText: 'Username',
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.grey,
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.blue,
width: 2,
),
),
),
)
23. Error Text
errorText can display an error message below the TextField.
TextField(
decoration: InputDecoration(
labelText: 'Email',
errorText: 'Please enter a valid email',
border: OutlineInputBorder(),
),
)
For larger forms with validation, TextFormField is generally more convenient because it integrates directly with Flutter's Form and validation APIs. :contentReference[oaicite:9]{index=9}
24. Read-Only TextField
Use readOnly: true when the user should be able to view the field but should not edit its contents.
TextField(
readOnly: true,
controller: TextEditingController(
text: 'User ID: 1001',
),
decoration: InputDecoration(
labelText: 'User ID',
border: OutlineInputBorder(),
),
)
25. Disabled TextField
The enabled property can disable the TextField.
TextField(
enabled: false,
decoration: InputDecoration(
labelText: 'Disabled Field',
border: OutlineInputBorder(),
),
)
26. Autofocus
autofocus: true requests focus when the field is initially displayed.
TextField(
autofocus: true,
decoration: InputDecoration(
labelText: 'Search',
border: OutlineInputBorder(),
),
)
27. Text Input Formatter
inputFormatters can be used to control or transform user input.
Import the services package:
import 'package:flutter/services.dart';
Digits Only
TextField(
keyboardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
],
decoration: InputDecoration(
labelText: 'Enter Number',
border: OutlineInputBorder(),
),
)
Maximum Length with Formatter
TextField(
inputFormatters: [
LengthLimitingTextInputFormatter(10),
],
decoration: InputDecoration(
labelText: 'Input',
border: OutlineInputBorder(),
),
)
28. FocusNode
FocusNode allows you to control and monitor keyboard focus.
class FocusExample extends StatefulWidget {
const FocusExample({super.key});
@override
State createState() => _FocusExampleState();
}
class _FocusExampleState extends State {
final FocusNode nameFocus = FocusNode();
@override
void dispose() {
nameFocus.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return TextField(
focusNode: nameFocus,
decoration: const InputDecoration(
labelText: 'Name',
border: OutlineInputBorder(),
),
);
}
}
29. Moving Focus Between TextFields
Focus can be moved from one input field to another after the user submits the first field.
class LoginFields extends StatefulWidget {
const LoginFields({super.key});
@override
State createState() => _LoginFieldsState();
}
class _LoginFieldsState extends State {
final FocusNode emailFocus = FocusNode();
final FocusNode passwordFocus = FocusNode();
@override
void dispose() {
emailFocus.dispose();
passwordFocus.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
focusNode: emailFocus,
textInputAction: TextInputAction.next,
onSubmitted: (_) {
FocusScope.of(context).requestFocus(passwordFocus);
},
decoration: const InputDecoration(
labelText: 'Email',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 16),
TextField(
focusNode: passwordFocus,
obscureText: true,
decoration: const InputDecoration(
labelText: 'Password',
border: OutlineInputBorder(),
),
),
],
);
}
}
30. Hiding the Keyboard
You can remove keyboard focus by using FocusScope.
FocusScope.of(context).unfocus();
Example
ElevatedButton(
onPressed: () {
FocusScope.of(context).unfocus();
},
child: const Text('Hide Keyboard'),
)
31. Complete Login Form Example
import 'package:flutter/material.dart';
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@override
State createState() => _LoginPageState();
}
class _LoginPageState extends State {
final emailController = TextEditingController();
final passwordController = TextEditingController();
bool hidePassword = true;
@override
void dispose() {
emailController.dispose();
passwordController.dispose();
super.dispose();
}
void login() {
final email = emailController.text.trim();
final password = passwordController.text;
if (email.isEmpty || password.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Please enter email and password'),
),
);
return;
}
print('Email: $email');
print('Password: $password');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Login'),
),
body: Padding(
padding: const EdgeInsets.all(20),
child: Column(
children: [
TextField(
controller: emailController,
keyboardType: TextInputType.emailAddress,
decoration: const InputDecoration(
labelText: 'Email',
hintText: 'Enter your email',
prefixIcon: Icon(Icons.email),
border: OutlineInputBorder(),
),
),
const SizedBox(height: 16),
TextField(
controller: passwordController,
obscureText: hidePassword,
decoration: InputDecoration(
labelText: 'Password',
prefixIcon: const Icon(Icons.lock),
suffixIcon: IconButton(
icon: Icon(
hidePassword
? Icons.visibility
: Icons.visibility_off,
),
onPressed: () {
setState(() {
hidePassword = !hidePassword;
});
},
),
border: const OutlineInputBorder(),
),
),
const SizedBox(height: 24),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: login,
child: const Text('Login'),
),
),
],
),
),
);
}
}
32. TextField vs TextFormField
| Feature | TextField | TextFormField |
|---|
| Basic text input | Yes | Yes |
| InputDecoration | Yes | Yes |
| Controller | Yes | Yes |
| Form integration | No direct integration | Yes |
| Validator | Not built in as a FormField | Yes |
| onChanged | Yes | Yes |
| Password input | Yes | Yes |
| Best suited for | Individual input fields | Validated forms |
TextFormField wraps a TextField and integrates it with a surrounding Form, making it useful for form validation and saving form data. :contentReference[oaicite:10]{index=10}
33. Complete Registration Form Example
import 'package:flutter/material.dart';
class RegisterPage extends StatefulWidget {
const RegisterPage({super.key});
@override
State createState() => _RegisterPageState();
}
class _RegisterPageState extends State {
final nameController = TextEditingController();
final emailController = TextEditingController();
final phoneController = TextEditingController();
@override
void dispose() {
nameController.dispose();
emailController.dispose();
phoneController.dispose();
super.dispose();
}
void registerUser() {
final name = nameController.text.trim();
final email = emailController.text.trim();
final phone = phoneController.text.trim();
if (name.isEmpty || email.isEmpty || phone.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Please fill all fields'),
),
);
return;
}
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Registration successful'),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Register'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
children: [
TextField(
controller: nameController,
textCapitalization: TextCapitalization.words,
decoration: const InputDecoration(
labelText: 'Full Name',
prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
),
),
const SizedBox(height: 16),
TextField(
controller: emailController,
keyboardType: TextInputType.emailAddress,
decoration: const InputDecoration(
labelText: 'Email',
prefixIcon: Icon(Icons.email),
border: OutlineInputBorder(),
),
),
const SizedBox(height: 16),
TextField(
controller: phoneController,
keyboardType: TextInputType.phone,
decoration: const InputDecoration(
labelText: 'Phone Number',
prefixIcon: Icon(Icons.phone),
border: OutlineInputBorder(),
),
),
const SizedBox(height: 24),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: registerUser,
child: const Text('Register'),
),
),
],
),
),
);
}
}
34. Search TextField Example
class SearchExample extends StatefulWidget {
const SearchExample({super.key});
@override
State createState() => _SearchExampleState();
}
class _SearchExampleState extends State {
String searchText = '';
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
onChanged: (value) {
setState(() {
searchText = value;
});
},
decoration: InputDecoration(
hintText: 'Search products...',
prefixIcon: const Icon(Icons.search),
suffixIcon: searchText.isNotEmpty
? IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
setState(() {
searchText = '';
});
},
)
: null,
border: const OutlineInputBorder(),
),
),
const SizedBox(height: 20),
Text('Search: $searchText'),
],
);
}
}
35. Important TextField Properties
| Property | Description |
|---|
controller | Controls and reads the field's text. |
focusNode | Controls keyboard focus. |
decoration | Controls the visual appearance. |
keyboardType | Controls the suggested keyboard type. |
textInputAction | Controls the keyboard action button. |
obscureText | Hides sensitive input such as passwords. |
maxLines | Controls the maximum number of lines. |
minLines | Controls the minimum number of lines. |
maxLength | Limits input length. |
readOnly | Prevents editing while allowing the field to remain visible. |
enabled | Enables or disables the field. |
autofocus | Requests focus when the field appears. |
textAlign | Controls horizontal text alignment. |
textCapitalization | Controls automatic capitalization. |
onChanged | Runs when the input value changes. |
onSubmitted | Runs when the user submits the input. |
inputFormatters | Restricts or transforms user input. |
36. Best Practices for TextField
- Use meaningful
labelText and hintText.
- Choose an appropriate
keyboardType for the expected input.
- Use
TextEditingController when the application needs to read or control the field value.
- Dispose controllers and FocusNodes when they are no longer needed.
- Use
obscureText for password fields.
- Use
TextFormField when working with validated forms.
- Use
inputFormatters when specific input formats are required.
- Use
maxLength when input length needs to be restricted.
- Use
maxLines for comments, descriptions, and other multiline content.
- Use clear validation messages for invalid input.
- Avoid creating controllers repeatedly inside the
build() method.
- Use
SingleChildScrollView or another appropriate scrolling layout when many fields can be hidden by the keyboard.
37. Common Mistakes
Mistake 1: Not Disposing Controllers
@override
void dispose() {
nameController.dispose();
super.dispose();
}
Mistake 2: Using the Wrong Keyboard Type
For example, an email field should generally use:
keyboardType: TextInputType.emailAddress
Mistake 3: Forgetting Password Obscuring
TextField(
obscureText: true,
)
Mistake 4: Using TextField for Complex Form Validation
For forms containing multiple validated fields, consider TextFormField with a Form.
38. Practical Exercise
Create a Flutter registration screen containing the following fields:
- Full Name
- Email Address
- Phone Number
- Password
- Confirm Password
- Address
Requirements:
- Use
TextEditingController for each required field.
- Use appropriate keyboard types.
- Hide password characters.
- Use prefix icons.
- Use outlined borders.
- Use maximum length where appropriate.
- Use multiline input for the address.
- Add a Register button.
- Display a message after successful submission.
39. Interview Questions
- What is TextField in Flutter?
- What is the purpose of InputDecoration?
- What is TextEditingController?
- Why should TextEditingController be disposed?
- What is the difference between onChanged and onSubmitted?
- How do you create a password field?
- How can you change the keyboard type?
- How do you create a multiline TextField?
- What is the use of maxLength?
- What is the difference between readOnly and enabled?
- What is FocusNode?
- How can you move focus from one TextField to another?
- What is TextFormField?
- What is the difference between TextField and TextFormField?
- How can inputFormatters be used?
- How can you customize the focused border?
- How do you retrieve the value from a TextField?
40. Quick Revision
| Concept | Example |
|---|
| Basic field | TextField() |
| Label | labelText: 'Name' |
| Hint | hintText: 'Enter name' |
| Controller | controller: nameController |
| Read value | controller.text |
| Password | obscureText: true |
| Email keyboard | keyboardType: TextInputType.emailAddress |
| Multiline | maxLines: 5 |
| Character limit | maxLength: 20 |
| Input changes | onChanged |
| Submit | onSubmitted |
| Focus control | FocusNode |
| Form validation | TextFormField |
41. Key Takeaways
TextField is the basic Flutter widget for accepting editable text input.
InputDecoration is used to customize the appearance of the field.
TextEditingController provides programmatic access to the input value.
onChanged responds to changes while the user types.
onSubmitted responds when the user submits the field.
obscureText is useful for password input.
keyboardType improves the input experience by providing an appropriate keyboard.
maxLines supports multiline input.
inputFormatters can restrict or transform user input.
FocusNode can be used for advanced focus management.
TextFormField is useful when TextField input needs to participate in a Form with validation.
42. Official Flutter Resources
43. JustAcademy Flutter Resources
Learn more about Flutter development through the following resources: